package web.sms.mvc.service.impl;

import cn.palerock.core.shiro.useradmin.auditor.UserAuditor;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import web.sms.core.exception.ServiceException;
import web.sms.core.exception.shiro.ServiceExceptionCallback;
import web.sms.core.pojo.ErrorInfo;
import web.sms.mvc.constant.DepartureConstant;
import web.sms.mvc.dao.DepartureMapper;
import web.sms.mvc.entity.Departure;
import web.sms.mvc.entity.User;
import web.sms.mvc.entity.pojo.DriverDepartureInfo;
import web.sms.mvc.service.DepartureService;
import web.sms.mvc.service.UserService;
import web.sms.utils.ObjectUtils;

import java.util.Date;
import java.util.List;

/**
 * 时间： 2018/1/2
 *
 * @author Eoly
 */
@Service
public class DepartureServiceImpl implements DepartureService {

    private final DepartureMapper departureMapper;
    private final UserAuditor userAuditor;
    private final UserService userService;

    @Autowired
    public DepartureServiceImpl(DepartureMapper departureMapper, UserAuditor userAuditor, UserService userService) {
        this.departureMapper = departureMapper;
        this.userAuditor = userAuditor;
        this.userService = userService;
    }

    @Override
    public void addDeparture(Departure departure) {
        // 检查权限
        userAuditor.checkPerms("departure:admin|departure:add");
        // 检测属性
        ObjectUtils.checkObjectProperties(departure, DepartureConstant.ADD_DEPARTURE_ERROR,
                "departureDriverId",
                "departureAimPlace", "departureTransition", "departureCostMoney",
                "departureCostMoneyDesc", "departureCostTime", "departureCostTimeDesc");
        // 清空不能设置的属性
        ObjectUtils.emptyUserProperties(departure, DepartureConstant.ADD_DEPARTURE_ERROR,
                "departureId", "departureInitiatorId", "departureStartTime",
                "departureBackTime", "departureReceiverId", "departureOvertimeResult",
                "departureRealCostTime");
        // 获得当前操作用户的id
        Integer id = (Integer) userAuditor.getCurrentSubjectUniqueKey(new ServiceExceptionCallback());
        // 设置车单发起人为当前用户
        departure.setDepartureInitiatorId(id);
        // 检查司机是否合法
        userService.hasRole(departure.getDepartureDriverId(), "driver", new ErrorInfo(
                DepartureConstant.ADD_DEPARTURE_ERROR, DepartureConstant.DRIVER_IS_NOT_EXIST
        ));
        if (departure.getDepartureFirstCustomerId() != null) {
            // 核对首达客户
            User customer = userService.findUserWithBaseInfo(departure.getDepartureFirstCustomerId());
            ObjectUtils.checkObjectProperties(customer, new ErrorInfo(
                    DepartureConstant.ADD_DEPARTURE_ERROR,
                    DepartureConstant.CUSTOMER_CAN_NOT_FIND
            ));
            departure.setDepartureFirstCustomerName(customer.getUserRealName());
        }
        if (departure.getDepartureFirstCustomerName() == null) {
            // 首达客户名不能为空
            throw new ServiceException(DepartureConstant.FIRST_CUSTOMER_CAN_NOT_EMPTY);
        }
        // 执行添加操作
        this.addDepartureWithoutChecking(departure, null);
    }

    @Override
    public void doDispenseDriverForDeparture(Integer departureId, Integer driverId) {
        // 获取车单的具体信息
        Departure departure = this.getDeparture(departureId,
                DepartureConstant.DISPENSE_DRIVER_ERROR);
        ObjectUtils.checkObjectProperties(departure, DepartureConstant.DISPENSE_DRIVER_ERROR,
                "departureInitiatorId");
        // 检查权限
        userAuditor.checkPerms("departure:admin", departure.getDepartureInitiatorId());
        // 检查车单状态，车单只能在处于未接单状态才能分配司机
        if (departure.getDepartureStatus() != Departure.UNANSWERED) {
            throw new ServiceException(DepartureConstant.DISPENSE_DRIVER_ERROR,
                    DepartureConstant.DEPARTURE_IS_NOT_IN_UNANSWERED);
        }
        // 检查司机是否合法
        userService.hasRole(departure.getDepartureDriverId(), "driver", new ErrorInfo(
                DepartureConstant.DISPENSE_DRIVER_ERROR, DepartureConstant.DRIVER_IS_NOT_EXIST
        ));
        // 分配司机操作
        Departure editDeparture = new Departure();
        editDeparture.setDepartureId(departureId);
        editDeparture.setDepartureDriverId(driverId);
        this.editDepartureWithChecking(editDeparture, DepartureConstant.DISPENSE_DRIVER_FAILURE);
    }

    @Override
    public PageInfo<Departure> findClerkDepartures(Integer pageNum, Integer pageSize) {
        // 检查权限
        userAuditor.checkPerms("departure:admin|departure:find");
        // 分页
        if (pageNum != null && pageSize != null) {
            PageHelper.startPage(pageNum, pageSize);
        }
        List<Departure> departures = departureMapper.selectAllDepartures();
        return new PageInfo<Departure>(departures);
    }

    @Override
    public PageInfo<Departure> findDriverDepartures(Integer driverId, Integer pageNum, Integer pageSize, Date startTime, Date endTime) {
        if (driverId == null) {
            // 获取当前用户的id
            driverId = (Integer) userAuditor.getCurrentSubjectUniqueKey(
                    new ServiceExceptionCallback());
        }
        // 检查权限
        userAuditor.checkPerms("departure:admin|departure:find", driverId);
        // 分页
        if (pageNum != null && pageSize != null) {
            PageHelper.startPage(pageNum, pageSize);
        }
        List<Departure> departures = departureMapper.selectDriverDepartures(driverId, startTime, endTime);
        if (departures == null || departures.size() == 0) {
            throw new ServiceException(DepartureConstant.EMPTY_DEPARTURES_LIST, 404);
        }
        return new PageInfo<Departure>(departures);
    }

    @Override
    public Departure findDepartureDetailInfo(Integer departureId) {
        Departure departure = departureMapper.selectDetailDepartureInfo(departureId);
        ObjectUtils.checkObjectProperties(departure, DepartureConstant.FIND_DEPARTURE_ERROR);
        return departure;
    }

    @Override
    public void makeSureDepartureReceipt(Integer departureId) {
        // 获取欲操作的派车单
        Departure departure = this.getDeparture(departureId, DepartureConstant.MODIFY_STATUS_ERROR);
        // 检查权限
        userAuditor.checkPerms("departure:admin|departure:add", departure.getDepartureDriverId());
        Integer status = departure.getDepartureStatus();
        // 判断派车单状态
        if (status != Departure.UNANSWERED) {
            throw new ServiceException(DepartureConstant.MODIFY_STATUS_ERROR,
                    DepartureConstant.IS_NOT_UNANSWERED_STATUS);
        }
        // 确定订单已接单
        Departure resultDeparture = new Departure();
        resultDeparture.setDepartureId(departureId);
        resultDeparture.setDepartureStatus(Departure.RECEIPT);
        this.editDepartureWithChecking(resultDeparture,
                DepartureConstant.MAKE_SURE_RECEIPT_FAILURE);
    }

    @Override
    public void doDeparting(Integer departureId) {
        // 检查权限
        userAuditor.checkPerms("departure:admin|departure:add");
        // 判断派车单状态
        this.checkDepartureStatus(departureId, Departure.RECEIPT,
                DepartureConstant.DO_DEPARTURE_ERROR);
        // 派车单发车操作
        Departure resultDeparture = new Departure();
        resultDeparture.setDepartureId(departureId);
        resultDeparture.setDepartureStatus(Departure.DELIVERING);
        resultDeparture.setDepartureStartTime(new Date());
        this.editDepartureWithChecking(resultDeparture,
                DepartureConstant.DO_DEPARTURE_FAILURE);
    }

    @Override
    public void doReceive(Integer departureId, Integer receiverId) {
        // 检查权限
        userAuditor.checkPerms("departure:admin|departure:add");
        if (receiverId == null) {
            throw new ServiceException(DepartureConstant.HAVE_TO_SET_RECEIVER);
        }
        // 必须设置回厂收货人
        this.doReceive(departureId, receiverId, null);
    }

    @Override
    public void doReceive(Integer departureId, String receiverName) {
        // 检查权限
        userAuditor.checkPerms("departure:admin|departure:add");
        // 必须设置回厂收货人
        if (receiverName == null || "".equals(receiverName)) {
            throw new ServiceException(DepartureConstant.HAVE_TO_SET_RECEIVER);
        }
        this.doReceive(departureId, null, receiverName);
    }

    /**
     * 回厂收货
     */
    private void doReceive(Integer departureId, Integer receiverId, String receiverName) {
        // 判断派车单状态
        this.checkDepartureStatus(departureId, Departure.DELIVERING,
                DepartureConstant.DO_RECEIVE_ERROR);
        // 获取派车单开始时间,计算时间
        Departure departure = this.getDeparture(departureId, DepartureConstant.MODIFY_STATUS_ERROR);
        Date startTime = departure.getDepartureStartTime();
        Date endTime = new Date();
        long subTime = endTime.getTime() - startTime.getTime();
        Double hoursCost = ((double) subTime) / 1000 / 60 / 60;
        // 核对回厂收货人
        if (receiverId != null) {
            User receiver = userService.findUserWithBaseInfo(receiverId);
            ObjectUtils.checkObjectProperties(receiver, new ErrorInfo(
                    DepartureConstant.DO_RECEIVE_ERROR,
                    DepartureConstant.RECEIVER_CAN_NOT_FIND
            ));
            receiverName = receiver.getUserRealName();
        }
        // 计算节约用时
        Double saveTime = departure.getDepartureCostTime() - hoursCost;
        if (saveTime >= 0) {
            throw new ServiceException(DepartureConstant.DO_RECEIVE_ERROR,
                    DepartureConstant.DEPARTURE_NOT_OVERTIME);
        }
        // 派车单回厂收货操作
        Departure resultDeparture = new Departure();
        resultDeparture.setDepartureId(departureId);
        resultDeparture.setDepartureStatus(Departure.ARRIVAL);
        resultDeparture.setDepartureBackTime(endTime);
        resultDeparture.setDepartureRealCostTime(hoursCost);
        resultDeparture.setDepartureReceiverName(receiverName);
        resultDeparture.setDepartureReceiverId(receiverId);
        this.editDepartureWithChecking(resultDeparture,
                DepartureConstant.DO_RECEIVE_FAILURE);
    }

    @Override
    public void changeDeparture(Departure departure) {

    }

    @Override
    public void doFillInResultOfLater(Integer departureId, String result) {
        // 获取操作派车单
        Departure departure = this.getDeparture(departureId,
                DepartureConstant.FILL_IN_RESULT_ERROR);
        // 获取操作司机的id
        Integer driverId = (Integer) userAuditor.getCurrentSubjectUniqueKey(new ServiceExceptionCallback());
        // 若该司机不属于该派车单则操作失败
        if (!driverId.equals(departure.getDepartureDriverId())) {
            throw new ServiceException(DepartureConstant.FILL_IN_RESULT_ERROR,
                    DepartureConstant.DEPARTURE_DRIVER_IS_NOT_MATCH);
        }
        // 检查派车单状态，并判断是否超时
        if (departure.getDepartureStatus() != Departure.ARRIVAL ||
                departure.getDepartureBackTime() == null ||
                departure.getDepartureStartTime() == null) {
            throw new ServiceException(DepartureConstant.FILL_IN_RESULT_ERROR,
                    DepartureConstant.DEPARTURE_IS_NOT_EXCEPT_TO_FILL_RESULT);
        }
        // 填写超时原因
        if (result == null || "".equals(result)) {
            throw new ServiceException(DepartureConstant.FILL_IN_RESULT_ERROR,
                    DepartureConstant.RESULT_IS_NOT_TO_BE_EMPTY);
        }
        Departure resultDeparture = new Departure();
        resultDeparture.setDepartureId(departureId);
        resultDeparture.setDepartureOvertimeResult(result);
        this.editDepartureWithChecking(resultDeparture, DepartureConstant.FILL_RESULT_FAILURE);
    }

    @Override
    public void deleteDeparture(Integer departureId) {
        userAuditor.checkPerms("departure:admin|departure:delete");
        this.deleteDepartureWithChecking(departureId);
    }

    @Override
    public Double getAllTimeCostInADriver(Integer driverId) {
        if (driverId == null) {
            throw new ServiceException(DepartureConstant.GET_DRIVER_INFO_ERROR,
                    DepartureConstant.DRIVER_IS_NOT_EXIST);
        }
        // 检查权限
        userAuditor.checkPerms("user:admin|user:find", driverId);
        Double timeCost = departureMapper.selectTotalCostTimeByDriverId(driverId);
        if (timeCost == null) {
            timeCost = 0d;
        }
        return timeCost;
    }

    @Override
    public DriverDepartureInfo findDriverInfoInCycle(Integer driverId, Date startTime,
                                                     Date endTime) {
        if (driverId == null) {
            throw new ServiceException(DepartureConstant.GET_DRIVER_INFO_ERROR,
                    DepartureConstant.DRIVER_IS_NOT_EXIST);
        }
        // 检查权限
        userAuditor.checkPerms("user:admin|user:find", driverId);
        DriverDepartureInfo driverDepartureInfo = departureMapper.selectDriverDepartureInfo(
                driverId, startTime, endTime
        );
        if (driverDepartureInfo == null) {
            throw new ServiceException(DepartureConstant.GET_DRIVER_INFO_ERROR,
                    DepartureConstant.NOT_EXIST_IN_THIS_TIME);
        }
        return driverDepartureInfo;
    }

    /**
     * 私
     * 修改派车单实体属性，无需检查
     *
     * @param departure 派车单实体
     * @param doFailMsg 当修改失败时的提示信息，null为使用默认提示信息
     */
    private void editDepartureWithChecking(Departure departure, String doFailMsg) {
        if (departure.getDepartureId() == null) {
            throw new ServiceException(DepartureConstant.OPTION_ERROR,
                    DepartureConstant.DEPARTURE_NOT_EXIST);
        }
        // 修改操作
        int result = departureMapper.updateByPrimaryKeySelective(departure);
        if (result < 1) {
            if (doFailMsg == null) {
                throw new ServiceException(DepartureConstant.SERVER_RUN_SQL_FAILURE,
                        DepartureConstant.EDIT_DEPARTURE_FAILURE);
            } else {
                throw new ServiceException(DepartureConstant.SERVER_RUN_SQL_FAILURE,
                        doFailMsg);
            }
        }
    }

    /**
     * 私
     * 添加派车单
     *
     * @param departure 派车单实体
     * @param doFailMsg 当添加失败时的提示信息，null为使用默认提示信息
     */
    private void addDepartureWithoutChecking(Departure departure, String doFailMsg) {
        // 添加操作
        int result = departureMapper.insertSelective(departure);
        if (result < 1) {
            if (doFailMsg == null) {
                throw new ServiceException(DepartureConstant.SERVER_RUN_SQL_FAILURE,
                        DepartureConstant.ADD_DEPARTURE_FAILURE);
            } else {
                throw new ServiceException(DepartureConstant.SERVER_RUN_SQL_FAILURE,
                        doFailMsg);
            }
        }
    }

    /**
     * 私
     * 删除派车单
     *
     * @param departureId 派车单id
     */
    private void deleteDepartureWithChecking(Integer departureId) {
        Departure deleteDeparture = new Departure();
        deleteDeparture.setDepartureId(departureId);
        deleteDeparture.setDepartureStatus(Departure.NOT_EXIST);
        this.editDepartureWithChecking(deleteDeparture,
                DepartureConstant.DELETE_DEPARTURE_FAILURE);
    }

    /**
     * 私
     * 查询车单
     *
     * @param departureId 车单id
     * @param doFailInfo  操作失败时的信息实体
     * @return 车单实体
     */
    private Departure getDeparture(Integer departureId, ErrorInfo doFailInfo) {
        if (departureId == null) {
            throw new ServiceException(doFailInfo, DepartureConstant.DEPARTURE_NOT_EXIST);
        }
        Departure departure = departureMapper.selectByPrimaryKey(departureId);
        if (departure == null) {
            throw new ServiceException(doFailInfo, DepartureConstant.DEPARTURE_NOT_EXIST);
        }
        return departure;
    }

    /**
     * 检查车单状态
     *
     * @param departureId 车单id
     * @param aimStatus   目标状态
     * @param failInfo    检查失败的错误信息
     */
    private void checkDepartureStatus(Integer departureId,
                                      int aimStatus, ErrorInfo failInfo) {
        // 获取欲操作的派车单
        Departure departure = this.getDeparture(departureId, DepartureConstant.MODIFY_STATUS_ERROR);
        Integer status = departure.getDepartureStatus();
        // 判断派车单状态
        String errorMsg = "";
        if (!status.equals(aimStatus)) {
            switch (aimStatus) {
                case Departure.ARRIVAL:
                    errorMsg = DepartureConstant.ARRIVAL_STATUS_EXCEPT;
                    break;
                case Departure.DELIVERING:
                    errorMsg = DepartureConstant.DELIVERING_STATUS_EXCEPT;
                    break;
                case Departure.RECEIPT:
                    errorMsg = DepartureConstant.RECEIPT_STATUS_EXCEPT;
                    break;
                case Departure.UNANSWERED:
                    errorMsg = DepartureConstant.UNANSWERED_STATUS_EXCEPT;
                    break;
                default:
            }
            throw new ServiceException(failInfo, errorMsg);
        }
    }
}
